package com.itsky.java.ai.longchain4j.Controller;

import com.alibaba.dashscope.aigc.multimodalconversation.AudioParameters;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.exception.UploadFileException;
import com.itsky.java.ai.longchain4j.assistant.XiaozhiAgent;
import com.itsky.java.ai.longchain4j.bean.ChatForm;
import io.reactivex.Flowable;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Sinks;

import javax.sound.sampled.*;
import java.util.Base64;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Tag(name = "硅谷小智")
@RestController
@RequestMapping("/xiaozhi")
public class XiaozhiController {
    // 添加类成员变量
    private final ExecutorService audioExecutor = Executors.newSingleThreadExecutor();
    private static final String MODEL = "qwen-tts";
    //    构造器注入bean、设置器注入、字段注入
    @Autowired
    private XiaozhiAgent xiaozhiAgent;

    @Operation(summary = "对话")
    @PostMapping(value = "/chat", produces = "text/stream;charset=utf-8")
    //    改为utf-8字节编码防止乱码，并返回text/stream类型数据
    public Flux<String> chat(@RequestBody ChatForm chatForm) {
        StringBuilder buffer = new StringBuilder();

        return xiaozhiAgent.chat(chatForm.getMemoryId(), chatForm.getMessage())
                .doOnNext(data -> {
                    buffer.append(data);  // 实时收集数据
                    System.out.print(data); // 可选：实时输出片段
                })
                .doOnComplete(() -> {
                    try {
                        streamCall(buffer.toString());
                        System.out.println("\n最终结果：" + buffer);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                })
                .doOnError(error -> System.err.println("处理异常: " + error.getMessage()))
                .doFinally(signal -> System.out.println("流处理完成状态: " + signal));
    }

    /*--------------------------------------------------*/
//    TTS语音播放
    public void streamCall(String context) throws ApiException, NoApiKeyException, UploadFileException {
        MultiModalConversation conv = new MultiModalConversation();
        MultiModalConversationParam param = MultiModalConversationParam.builder()
                .apiKey("sk-9781f55fc367425c87c47abcc9f4a776")
                .model(MODEL)
                .text(context)
                .voice(AudioParameters.Voice.CHELSIE)
                .build();
        Flowable<MultiModalConversationResult> result = conv.streamCall(param);

        // 修改后的播放逻辑
        result.blockingForEach(r -> audioExecutor.execute(() -> {
            try {
                // 1. 获取Base64编码的音频数据
                String base64Data = r.getOutput().getAudio().getData();
                byte[] audioBytes = Base64.getDecoder().decode(base64Data);
                // 2. 配置音频格式（根据API返回的音频格式调整）
                AudioFormat format = new AudioFormat(
                        AudioFormat.Encoding.PCM_SIGNED,
                        24000, // 采样率（需与API返回格式一致）
                        16,    // 采样位数
                        1,     // 声道数
                        2,     // 帧大小（位数/字节数）
                        16000, // 新数据传输率（44100）
                        false  // 是否压缩
                );

                // 3.优化播放流畅度：
                //增加分块写入机制（4096字节/块）
                //使用独立线程池处理音频播放
                //添加设备重试逻辑（最大3次）
                for (int retry = 0; retry < 3; retry++) {
                    try (SourceDataLine line = AudioSystem.getSourceDataLine(format)) {
                        line.open(format);
                        line.start();

                        int chunkSize = 4096;
                        for (int offset = 0; offset < audioBytes.length; offset += chunkSize) {
                            int length = Math.min(chunkSize, audioBytes.length - offset);
                            line.write(audioBytes, offset, length);
                        }

                        line.drain();
                        break; // 成功则退出重试循环
                    } catch (LineUnavailableException e) {
                        if (retry == 2) throw e;
                        Thread.sleep(500); // 500ms后重试
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }));
    }
}
